import java.util.LinkedList;

public class Scanner {
	private String source;
	private LinkedList<Token> tokenList;
	
	public Scanner(String sourceString){
		source = sourceString;
		//tokenList.add("Start");
		tokenList = new LinkedList<Token>(); 
		System.out.print("Scanner started");
	}
	
	public Scanner(){
	    tokenList = new LinkedList<Token>(); 
	    //tokenList.add("Start");
	    //System.out.print("Scanner started\r\n");
	}
	
	public void setSource(String s) {
	    this.source = s;
	}
	
	//scan the whole input sting to generate a list containing all of words from input in order.
	public LinkedList<Token> scan(){
		//Do scan here
	    int sourceLength = source.length();
		int index = 0;
		int start, end  = 0;
		char nextChar = source.charAt(0);
		while(index < sourceLength - 1){
		    //blank characters
			if(nextChar == ' ' ||  nextChar == '\r' || nextChar == '\n' || nextChar == '\t'){
				index ++;
				nextChar = source.charAt(index);
				continue;
			}else
			//tokens
			{
			    //Single character token, most operator or other punctuation
			    switch(nextChar = source.charAt(index)) {
			    case '(':case ')':case '+':case '@':case '&':case '=':case ';':
			    case ',':case '~':case '|':case '$':case '!':case '%':case '^':case '#':
			    case '[':case ']':case '{':case '}':case '?':case '.':
			        tokenList.add(new Token(TokenType.Rpal_Punctuation, String.valueOf(nextChar)));
			        index ++;
			        continue;
			        
			    case '*'://* and ** operator
			        if(source.charAt(index+1) == '*')
			        {
			            tokenList.add(new Token(TokenType.Rpal_Operator, "**"));
			            index += 2;
			        }
			        else
			        {
			            tokenList.add(new Token(TokenType.Rpal_Operator, "*"));
			            index ++;
			        }
			        continue;
			        
			    case '-'://- and -> operator
			        if(source.charAt(index+1) == '>')
                    {
                        tokenList.add(new Token(TokenType.Rpal_Operator, "->"));
                        index += 2;
                    }
                    else
                    {
                        tokenList.add(new Token(TokenType.Rpal_Operator, "-"));
                        index ++;
                    }
                    continue;
			    
			    case '/'://'/' or //
			        if(source.charAt(index+1) == '/')
                    {   //skip comments
                        while(nextChar != '\r') {
                            nextChar = source.charAt(index ++);
                        }
			   nextChar = source.charAt(index);
                    }
                    else
                    {
                        tokenList.add(new Token(TokenType.Rpal_Operator, "/"));
                        index ++;
                    }
                    continue;
                    
			    case '\''://string
			        start = index;
			        end = index + 1;
			        nextChar = source.charAt(end);
                    while(nextChar != '\'' ) {
                        nextChar = source.charAt(end++);
                    }
                    if(end - start > 1) {
                        tokenList.add(new Token(TokenType.Rpal_String, source.substring(start, end )));
                        start = index = end;
                    }
                    else {
                        tokenList.add(new Token(TokenType.Rpal_String, source.substring(start, end+1 ))); 
                        start = index = end + 1;    
                    }
                    continue;
                    
                    
                //integer
			    case '0':case '1':case '2':case '3':case '4':
			    case '5':case '6':case '7':case '8':case '9':
			        start = end = index;
			        while((nextChar =  source.charAt(end)) > 47 && nextChar < 58 ) {
                        end ++;
			        }
			        tokenList.add(new Token(TokenType.Rpal_Integer, source.substring(start, end)));
			        start = index = end;	
			        continue;
			    
			    case 'q':case 'w':case 'e':case 'r':case 't':case 'y':
			    case 'u':case 'i':case 'o':case 'p':case 'a':case 's':
			    case 'd':case 'f':case 'g':case 'h':case 'j':case 'k':
			    case 'l':case 'z':case 'x':case 'c':case 'v':case 'b':
			    case 'n':case 'm':case 'Q':case 'W':case 'E':case 'R':
                case 'T':case 'Y':case 'U':case 'I':case 'O':case 'P':
                case 'A':case 'S':case 'D':case 'F':case 'G':case 'H':
                case 'J':case 'K':case 'L':case 'Z':case 'X':case 'C':
                case 'V':case 'B':case 'N':case 'M':case '_':
                    start = end = index;
                    while(((nextChar = source.charAt(end)) > 64 && nextChar < 91) 
                            || (nextChar > 96 && nextChar < 123) 
                            || nextChar == '_' 
                            || (nextChar > '0' && nextChar < '9')){
                        
                        end ++;
                        
                    }
                    
                    tokenList.add(new Token(isKeyWord( source.substring(start, end ).trim()), source.substring(start, end ).trim()));
                    start = index = end;    
                    continue;
			    }
			}
		}
		tokenList.add(new Token(TokenType.Rpal_EndOfFile,"EOF"));
		return this.tokenList;
			
	}
	
	private TokenType isKeyWord(String s) {
	    if( s.equals("let") || 
            s.equals("within") || 
            s.equals("in") || 
            s.equals("rec") || 
            s.equals("fn") || 
            s.equals("and") || 
            s.equals("aug") || 
            s.equals("or") || 
            s.equals("not") || 
            s.equals("gr") || 
            s.equals("ge") || 
            s.equals("ls") || 
            s.equals("le") || 
            s.equals("eq") || 
            s.equals("ne") || 
            s.equals("true") || 
            s.equals("false") || 
            s.equals("where") ||
            s.equals("dummy") ||
            s.equals("nil") ) {
	        return TokenType.Rpal_Keyword;
	    }else {
	        return TokenType.Rpal_Identirfier;
	    }
	}
	
	public Token readNextToken(){
		return tokenList.poll();
	}
	
	public Token touchNextToken(){
		return tokenList.peek();
	}
	
}
